package me.zhengjie.controller.outBound;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.annotation.Log;
import me.zhengjie.dto.*;
import me.zhengjie.dto.sqlServer.*;
import me.zhengjie.domain.OutBoundService;
import me.zhengjie.repository.*;
import me.zhengjie.service.*;
import me.zhengjie.service.dto.OutBoundOrderDto;
import me.zhengjie.service.dto.OutBoundOrderQueryCriteria;
import me.zhengjie.utils.PageResult;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequiredArgsConstructor
@Slf4j
@Api(tags = "出库管理")
@RequestMapping("/api/outBound")
public class OutBoundController {

    private final OutBoundService outBoundService;
    private final OutBoundOrderService outBoundOrderService;
    private final OutBoundOrderDetailService outBoundOrderDetailService;
    private final InventoryService inventoryService;
    private final OutBoundMissionService outBoundMissionService;
    private final StorageService storageService;
    private final ReservoirAreaRepository reservoirAreaRepository;
    private final PalletRepository palletRepository;
    private final ProcesscardRepository processcardRepository;
    private final PressMachineRepository pressMachineRepository;


    @GetMapping
    @Log("查询出库单")
    @ApiOperation("查询出库单")
    @PreAuthorize("@el.check('outBoundOrder:list')")
    public ResponseEntity<PageResult<OutBoundOrderDto>> queryOutBoundOrder(OutBoundOrderQueryCriteria criteria, Pageable pageable){
        return new ResponseEntity<>(outBoundOrderService.queryAll(criteria,pageable), HttpStatus.OK);
    }

    @Log("查找出库单明细")
    @ApiOperation("查找出库单明细")
    @GetMapping(value = "/getOutBoundDetail/{orderId}")
    public List<OutBoundOrderDetailInfo> getOutBoundDetail(@PathVariable("orderId") Integer orderId){
        try {

            List<OutBoundOrderDetail> details = outBoundOrderDetailService.findByOrderId(orderId);
            ArrayList<OutBoundOrderDetailInfo> detailInfos = new ArrayList<>();
            details.forEach(x->{
                OutBoundOrderDetailInfo detailInfo = new OutBoundOrderDetailInfo();
                detailInfo.setId(x.getId());
                detailInfo.setOutBoundOrderId(orderId);
                detailInfo.setPalletId(palletRepository.findPalletCodeById(x.getPalletId()));
                detailInfos.add(detailInfo);
            });
             return detailInfos;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /*@Log("查找库存")
    @ApiOperation("查找出库信息")
    @GetMapping(value = "/getInventory/{workNum}/{zoneCode}/{processcardCode}")
    public Resp getInventory(@PathVariable("workNum") String workNum, @PathVariable("zoneCode")String zoneCode,@PathVariable("processcardCode")String processcardCode){
        List<Inventory> inventories = outBoundService.findInventoryByWorkNumAndZoneCode(workNum,zoneCode, processcardCode);
        if (inventories.isEmpty()){
            return Resp.builder()
                    .status(200)
                    .data("inventoryReports",inventories)
                    .msg("没有匹配到库存信息")
                    .build();
        }
        InventoryReport inventoryReport = new InventoryReport();
        inventoryReport.setCount(inventories.size());
        inventoryReport.setWorkNum(inventories.get(0).getWorkNum());
        Integer processcardId = inventories.get(0).getProcesscardId();
        Processcard processcard = processcardRepository.findProcesscardById(processcardId);
        inventoryReport.setProcesscardCode(processcard.getProcesscardCode());
        ArrayList<InventoryReport> inventoryReports = new ArrayList<>();
        inventoryReports.add(inventoryReport);
        return Resp.builder()
                .status(200)
                .data("inventoryReports",inventoryReports)
                .build();
    }*/

    @Log("查找库存")
    @ApiOperation("查找库存")
    @PostMapping(value = "/getInventory")
    public Resp getInventory(@RequestBody FindInventoryParameter parameter){
        List<Inventory> inventories = outBoundService.getInventoryByParameter(parameter);
        if (inventories.isEmpty()){
            return Resp.builder()
                    .status(200)
                    .data("inventoryReports",inventories)
                    .msg("没有匹配到库存信息")
                    .build();
        }

        List<Integer> processcardIds = inventories
                .stream()
                .map(Inventory::getProcesscardId)
                .distinct()
                .collect(Collectors.toList());

        log.info("processcardIds:{}", processcardIds);

        List<InventoryReport> inventoryReports = new ArrayList<>();

        for (Integer processcardId : processcardIds) {
            List<Inventory> inventoryList = inventories
                    .stream()
                    .filter(inventory -> inventory.getProcesscardId().equals(processcardId))
                    .collect(Collectors.toList());
            InventoryReport inventoryReport = new InventoryReport();
            inventoryReport.setCount(inventoryList.size());
            inventoryReport.setWorkNum(inventoryList.get(0).getWorkNum());
            Processcard processcard = processcardRepository.findProcesscardById(processcardId);
            inventoryReport.setProcesscardCode(processcard.getProcesscardCode());
            inventoryReports.add(inventoryReport);
        }

        log.info("inventoryReports:{}", inventoryReports);

        return Resp.builder()
                .status(200)
                .data("inventoryReports",inventoryReports)
                .build();
    }

    @Log("创建出库单")
    @ApiOperation("创建出库单")
    @PostMapping(value = "/createOutBoundOrder")
    @PreAuthorize("@el.check('createOutBoundOrder:list')")
    public Resp createOutBoundOrder(@RequestBody OutBoundParameter outBoundParameter){
        try {
            List<Inventory> allInventories = outBoundService.findInventoryByWorkNumAndZoneCode(outBoundParameter.getWorkNum(),outBoundParameter.getZoneCode(),outBoundParameter.getProcesscardCode());
            if (outBoundParameter.getQty()>allInventories.size()){
                return Resp.builder()
                        .status(500)
                        .msg("需求数量超过库存数量")
                        .build();
            }else {
                List<Inventory> inventories = outBoundService.getInventory(outBoundParameter);
                outBoundService.saveOutBoundOrder(outBoundParameter);
                List<OutBoundOrderDetail> outBoundOrderDetails = outBoundService.createOrderDetail(inventories);
                outBoundService.createOutBoundMission(outBoundOrderDetails);
                return Resp.builder()
                        .status(200)
                        .msg("获取成功")
                        .build();
            }
        } catch (Exception e) {
            return Resp.builder()
                    .status(500)
                    .msg("创建出库单信息不完整，请校验数据！")
                    .build();
        }
    }

    @Log("开始执行出库单")
    @ApiOperation("开始执行出库单")
    @GetMapping(value = "/startOrder/{orderId}/{flowTo}")
    @PreAuthorize("@el.check('startOutBoundOrder:list')")
    public Resp StartOrder(@PathVariable("orderId") Integer orderId, @PathVariable Integer flowTo){
        // 首先判断是否已经分配了压机
        Integer orderStatus = outBoundOrderService.findById(orderId).getOrderStatus();
        if (orderStatus.equals(1)){
            return Resp.builder()
                    .status(300)
                    .msg("该任务以开始执行，请勿重复点击")
                    .build();
        }
        List<OutBoundMission> outBoundMissions = outBoundMissionService.findOutBoundMissionByOrderId(orderId);

        boolean result = outBoundService.chooseFlowTo(orderId, flowTo);
        if (result) {
            outBoundService.createOutTask(outBoundMissions);
            outBoundOrderService.startOrder(orderId);
            return Resp.builder()
                    .status(200)
                    .msg("任务已下发至执行列表")
                    .build();
        }else {
            return Resp.builder()
                    .status(500)
                    .msg("出库流向选择失败")
                    .build();
        }

        /*outBoundService.createOutTask(outBoundMissions);
        outBoundOrderService.startOrder(orderId);
        return Resp.builder()
                .status(200)
                .msg("任务已下发至执行列表")
                .build();*/
    }

    @Log("手动出库")
    @ApiOperation("手动出库")
    @GetMapping(value = "/manualOutBound")
    public Resp getAllStorage(){
        try {
            /*List<List<List<List<Storage>>>> allStorages = new ArrayList<>();*/
            List<List<List<List<StorageMsg>>>> allStorageMsg = new ArrayList<>();
            /*List<List<List<Storage>>> areaStoragesA = new ArrayList<>();*/
            List<List<List<StorageMsg>>> areaStoragesAMsg = new ArrayList<>();
            /*List<List<List<Storage>>> areaStoragesB = new ArrayList<>();*/
            List<List<List<StorageMsg>>> areaStoragesBMsg = new ArrayList<>();
            /*List<List<Storage>> firstRowStoragesA = new ArrayList<>();*/
            List<List<StorageMsg>> firstRowStoragesAMsg = new ArrayList<>();
            /*List<List<Storage>> secondRowStoragesA = new ArrayList<>();*/
            List<List<StorageMsg>> secondRowStoragesAMsg = new ArrayList<>();
            /*List<List<Storage>> firstRowStoragesB = new ArrayList<>();*/
            List<List<StorageMsg>> firstRowStoragesBMsg = new ArrayList<>();
            /*List<List<Storage>> secondRowStoragesB = new ArrayList<>();*/
            List<List<StorageMsg>> secondRowStoragesBMsg = new ArrayList<>();

            for (int i = 1; i < 17; i++) {
                List<Storage> storages = storageService.findStoragesByRowAndWareHouseAreaAndLayerOrderByColumn(1, "A", i);
                firstRowStoragesAMsg.add(outBoundService.getStorageMsg(storages));
                /*firstRowStoragesA.add(storages);*/
            }
            for (int i = 1; i < 17; i++) {
                List<Storage> storages = storageService.findStoragesByRowAndWareHouseAreaAndLayerOrderByColumn(2, "A", i);
                secondRowStoragesAMsg.add(outBoundService.getStorageMsg(storages));
                /*secondRowStoragesA.add(storages);*/
            }
            areaStoragesAMsg.add(firstRowStoragesAMsg);
            areaStoragesAMsg.add(secondRowStoragesAMsg);
            /*areaStoragesA.add(firstRowStoragesA);
            areaStoragesA.add(secondRowStoragesA);*/


            for (int i = 1; i < 17; i++) {
                List<Storage> storages = storageService.findStoragesByRowAndWareHouseAreaAndLayerOrderByColumn(1, "B", i);
                firstRowStoragesBMsg.add(outBoundService.getStorageMsg(storages));
                /*firstRowStoragesB.add(storages);*/
            }

            for (int i = 1; i < 17; i++) {
                List<Storage> storages = storageService.findStoragesByRowAndWareHouseAreaAndLayerOrderByColumn(2, "B", i);
                secondRowStoragesBMsg.add(outBoundService.getStorageMsg(storages));
                /*secondRowStoragesB.add(storages);*/
            }
            areaStoragesBMsg.add(firstRowStoragesBMsg);
            areaStoragesBMsg.add(secondRowStoragesBMsg);
            /*areaStoragesB.add(firstRowStoragesB);
            areaStoragesB.add(secondRowStoragesB);*/

            allStorageMsg.add(areaStoragesAMsg);
            allStorageMsg.add(areaStoragesBMsg);
           /* allStorages.add(areaStoragesA);
            allStorages.add(areaStoragesB);*/

            return Resp.builder()
                    .data("data",allStorageMsg)
                    .build();
        } catch (Exception e) {
            return Resp.builder()
                    .status(500)
                    .msg("未获取到当前库存信息")
                    .build();
        }
    }

    @Log("获取所有的工程号")
    @ApiOperation("手动出库")
    @GetMapping(value = "/getAllWorkNum")
    public List<String> getAllWorkNum(){
        return outBoundService.getAllWorkNum();
    }

    @Log("查询所有批次号编码")
    @ApiOperation("查询所有批次号编码")
    @GetMapping(value = "/getAllProcesscardCode")
    public List<String> getAllProcesscardCode(){
        return outBoundService.getAllProcesscardCode();
    }

    @Log("删除出库单")
    @ApiOperation("删除出库单")
    @GetMapping(value = "/deleteOrder/{orderId}")
    public Resp deleteOrder(@PathVariable("orderId") Integer orderId){
        try {
            outBoundService.deleteOutBoundOrder(orderId);
            return Resp.builder()
                    .status(200)
                    .msg("删除出库单成功！")
                    .build();
        } catch (Exception e) {
            return Resp.builder()
                    .status(500)
                    .msg("删除出库单失败！")
                    .build();
        }
    }

    @Log("查找所有的压机")
    @ApiOperation("查找所有的压机")
    @GetMapping("/findAllMachine")
    public Resp findAllMachine(){
        return Resp.builder()
                .data("pressMachine",pressMachineRepository.findAll())
                .status(200)
                .build();
    }


}
